package org.budo.dubbo.protocol.http.util;

import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.serialize.Serialization;
import com.alibaba.dubbo.common.utils.StringUtils;

import lombok.extern.slf4j.Slf4j;

import org.budo.dubbo.protocol.http.Consts;
import org.budo.dubbo.protocol.http.dispatcher.servlet.ServletProtocolRequest;
import org.budo.dubbo.protocol.http.exporter.BudoDubboHttpExporter;
import org.budo.dubbo.protocol.http.invocation.adapter.ProtocolRequest;
import org.budo.dubbo.serialize.util.DubboSerializeUtil;
import org.budo.support.spring.context.aware.BudoApplicationContextAware;

import javax.servlet.http.HttpServletRequest;

/**
 * @author lmw
 */
@Slf4j
public class BudoSerializationUtil {
    private static final ExtensionLoader<Serialization> SERIALIZATION_EXTENSION_LOADER = ExtensionLoader.getExtensionLoader(Serialization.class);

    private static final String CURRENT_REQUEST_SERIALIZATION_KEY = "currentRequestSerialization";

    /**
     * 将Json反序列化为对象
     */
    public static <T> T deserialize(Serialization serialization, byte[] responseData, Class<T> resultClass) {
        try {
            return DubboSerializeUtil.deserialize(serialization, responseData, resultClass);
        } catch (Throwable e) {
            log.error("#35 deserialize error, serialization=" + serialization + ", resultClass=" + resultClass + ", data=" + new String(responseData));
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 Serialization
     */
    public static Serialization getSerialization(ProtocolRequest protocolRequest) {
        HttpServletRequest request = ((ServletProtocolRequest) protocolRequest).getRequest();

        Serialization serialization = (Serialization) request.getAttribute(CURRENT_REQUEST_SERIALIZATION_KEY);
        if (null != serialization) {
            return serialization;
        }

        String serializationKey = getSerializationKey(request);
        serialization = SERIALIZATION_EXTENSION_LOADER.getExtension(serializationKey);
        if (null != serialization) {
            request.setAttribute(CURRENT_REQUEST_SERIALIZATION_KEY, serialization);
        }

        return serialization;
    }

    /**
     * 从 header 中读取序列化Key
     */
    private static String getSerializationKey(HttpServletRequest request) {
        String serializationKey = request.getParameter(Consts.HeaderKey.Serialization_2);

        if (StringUtils.isEmpty(serializationKey)) {
            serializationKey = request.getHeader(Consts.HeaderKey.Serialization_2);
        }

        if (StringUtils.isEmpty(serializationKey)) {
            serializationKey = request.getParameter(Consts.HeaderKey.Serialization);
        }

        if (StringUtils.isEmpty(serializationKey)) {
            serializationKey = request.getHeader(Consts.HeaderKey.Serialization);
        }

        BudoDubboHttpExporter exporter = BudoApplicationContextAware.getBeanCached_2(BudoDubboHttpExporter.class);
        if (null != exporter && null != exporter.getSerialization()) {
            serializationKey = exporter.getSerialization();
        }

        if (StringUtils.isEmpty(serializationKey)) {
            serializationKey = Consts.SerializationDefault;
        }

        return serializationKey;
    }
}
